/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.gitee.kamismile.stone.rpc.common.support;


import com.gitee.kamismile.stone.rpc.common.provider.consumer.StoneConsumerVersion;
import org.apache.commons.lang3.StringUtils;

import java.io.Serializable;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;


public class StoneURL implements Serializable {

    private static final long serialVersionUID = -1985165475234910535L;

    private String host;
    private int port;

    private  String coreThreads;
    private  String maxThreads;
    private  String maxIdleInSecond;
    private  String maxQueueSize;

    private String username;
    private String password;

    //权重 1-100
    private AtomicInteger weight = new AtomicInteger(100);
    //调用次数
    private AtomicInteger calls = new AtomicInteger(0);

    private Map<String, String> parameters = new HashMap<>();

    private transient String serviceKey;


    private String serverName;
    private String methodName;
    private int timeout;
    private int retry;
    private transient Class<?>[] parameterTypes;
    private Object[] arguments;

    private StoneConsumerVersion stoneConsumerVersion;

    private long numberVersion;

    private volatile transient Map<String, Number> numbers;

    public String getCoreThreads() {
        return coreThreads;
    }

    public void setCoreThreads(String coreThreads) {
        this.coreThreads = coreThreads;
    }

    public String getMaxThreads() {
        return maxThreads;
    }

    public void setMaxThreads(String maxThreads) {
        this.maxThreads = maxThreads;
    }

    public String getMaxIdleInSecond() {
        return maxIdleInSecond;
    }

    public void setMaxIdleInSecond(String maxIdleInSecond) {
        this.maxIdleInSecond = maxIdleInSecond;
    }

    public String getMaxQueueSize() {
        return maxQueueSize;
    }

    public void setMaxQueueSize(String maxQueueSize) {
        this.maxQueueSize = maxQueueSize;
    }

    public int getRetry() {
        return retry;
    }

    public void setRetry(int retry) {
        this.retry = retry;
    }

    public int getTimeout() {
        return timeout;
    }

    public void setTimeout(int timeout) {
        this.timeout = timeout;
    }

    public long getNumberVersion() {
        return getStoneConsumerVersion().getNumberVersion();
    }

    public StoneConsumerVersion getStoneConsumerVersion() {
        return stoneConsumerVersion;
    }

    public void setStoneConsumerVersion(StoneConsumerVersion stoneConsumerVersion) {
        this.stoneConsumerVersion = stoneConsumerVersion;
    }

    public int getWeight() {
        return weight.get();
    }


    public AtomicInteger getWeightAtomic() {
        return weight;
    }

    public void setWeightAtomic(AtomicInteger weight) {
        this.weight = weight;
    }

    public int getAndIncrement() {
        int get = getWeight();
        if (get > 99) {
            if(get>100){
                setWeightAtomic(new AtomicInteger(100));
            }
            return get;
        }
        return weight.getAndIncrement();
    }

    public int getAndDecrement() {
        int get = getWeight();
        if (get < 1) {
            return get;
        }
        return weight.getAndDecrement();
    }

    public AtomicInteger getCallsAtomic() {
        return calls;
    }

    public void setCallsAtomic(AtomicInteger calls) {
        this.calls = calls;
    }

    public int getCalls() {
        return calls.get();
    }

    public int getCallAndIncrement() {
        int get = getCalls();
        if (get > 100000000) {
            setCallsAtomic(new AtomicInteger(100000000));
            return get;
        }
        return calls.getAndIncrement();
    }

    public String getHost() {
        return host;
    }

    public void setHost(String host) {
        this.host = host;
    }

    public int getPort() {
        return port;
    }

    public void setPort(int port) {
        this.port = port;
    }

    public String getServerName() {
        return serverName;
    }

    public void setServerName(String serverName) {
        this.serverName = serverName;
    }

    public int getParameter(String key, int defaultValue) {
        Number n = getNumbers().get(key);
        if (n != null) {
            return n.intValue();
        }
        String value = getParameter(key);
        if (StringUtils.isEmpty(value)) {
            return defaultValue;
        }
        int i = Integer.parseInt(value);
        getNumbers().put(key, i);
        return i;
    }

    private Map<String, Number> getNumbers() {
        // concurrent initialization is tolerant
        if (numbers == null) {
            numbers = new ConcurrentHashMap<>();
        }
        return numbers;
    }

    public Map<String, String> getParameters() {
        return parameters;
    }

    public String getMethodName() {
        return methodName;
    }

    public void setMethodName(String methodName) {
        this.methodName = methodName;
    }

    public Class<?>[] getParameterTypes() {
        return parameterTypes;
    }

    public void setParameterTypes(Class<?>[] parameterTypes) {
        this.parameterTypes = parameterTypes;
    }

    public Object[] getArguments() {
        return arguments;
    }

    public void setArguments(Object[] arguments) {
        this.arguments = arguments;
    }

    public String getParameter(String key) {
        return parameters.get(key);
    }

    public void addParameter(String key, String value) {
        parameters.put(key, value);
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getServiceKey() {
        return serviceKey;
    }

    public void setServiceKey(String serviceKey) {
        this.serviceKey = serviceKey;
    }

}